package adapletplugin.editors;

import java.util.List;

import objects.AdapletConstants;
import objects.IObject;
import objects.Table;
import objects.Type;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.FormToolkit;

import sections.ISection.Section;
import util.ISectionListener;
import util.MatrixUtils;
import adapletplugin.dialogs.NewAttributeDialog;

public class TypeEditor extends AbstractSubEditor implements ISectionListener
{
	private Text fTypeNameText;
	private Combo fTableText;

	private Combo fDerivesText;

	private Combo fIdColText;
	private Combo fTypeColText;
	private Text fTypeAliasText;
	private Combo fNameColText;
	private Combo fRevColText;
	private Combo fPrevRevColText;
	private Combo fNextRevColText;
	private Combo fPolicyColText;
	private Combo fStateColText;
	private Combo fDescColText;
	private Combo fOwnerColText;
	private Combo fOrigColText;
	private Combo fModColText;
	
	private Type typeFocus;

	private Button fAllAttributesButton;
	private Button fNewAttributeButton;
	private TableViewer fAttributeTable;

	public TypeEditor(ScrolledComposite composite, FormToolkit toolkit, MapFileEditor parentEditor)
	{
		super(composite, toolkit, parentEditor);
		fMap.registerListener(Section.TABLE, this);
		fMap.registerListener(Section.TYPE, this);
	}

	@Override
	protected void create()
	{
		Composite row = fToolkit.createComposite(fSubComposite);
		row.setLayout(new GridLayout(2, false));
		row.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

		fToolkit.createLabel(row, "Type Name:");
		fTypeNameText = fToolkit.createText(row, "", SWT.BORDER | SWT.READ_ONLY);
		fTypeNameText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		//fTypeNameText.addModifyListener(createModifyListener_TypeName());

		fToolkit.createLabel(row, "Table Name:");
		fTableText = new Combo(row, SWT.BORDER);
		fTableText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fTableText.addModifyListener(createModifyListener_Table());

		fToolkit.createLabel(row, "Derives Type:");
		fDerivesText = new Combo(row, SWT.BORDER);
		fDerivesText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fDerivesText.addModifyListener(createModifyListener_Derives());

		fToolkit.createLabel(row, "ID Column:");
		fIdColText = new Combo(row, SWT.BORDER);
		fIdColText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fIdColText.addModifyListener(createModifyListener_ID());

		fToolkit.createLabel(row, "Type Column:");
		fTypeColText = new Combo(row, SWT.BORDER);
		fTypeColText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fTypeColText.addModifyListener(createModifyListener_Type());

		fToolkit.createLabel(row, "Type Alias:");
		fTypeAliasText = fToolkit.createText(row, "", SWT.BORDER);
		fTypeAliasText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fTypeAliasText.addModifyListener(createModifyListener_TypeAlias());

		fToolkit.createLabel(row, "Name Column:");
		fNameColText = new Combo(row, SWT.BORDER);
		fNameColText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fNameColText.addModifyListener(createModifyListener_Name());

		fToolkit.createLabel(row, "Revision Column:");
		fRevColText = new Combo(row, SWT.BORDER);
		fRevColText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fRevColText.addModifyListener(createModifyListener_Rev());

		fToolkit.createLabel(row, "Previous Revision Column:");
		fPrevRevColText = new Combo(row, SWT.BORDER);
		fPrevRevColText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fPrevRevColText.addModifyListener(createModifyListener_Prev());

		fToolkit.createLabel(row, "Next Revision Column:");
		fNextRevColText = new Combo(row, SWT.BORDER);
		fNextRevColText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fNextRevColText.addModifyListener(createModifyListener_Next());

		fToolkit.createLabel(row, "Policy Column:");
		fPolicyColText = new Combo(row, SWT.BORDER);
		fPolicyColText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fPolicyColText.addModifyListener(createModifyListener_Policy());

		fToolkit.createLabel(row, "State Column:");
		fStateColText = new Combo(row, SWT.BORDER);
		fStateColText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fStateColText.addModifyListener(createModifyListener_State());

		fToolkit.createLabel(row, "Description Column:");
		fDescColText = new Combo(row, SWT.BORDER);
		fDescColText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fDescColText.addModifyListener(createModifyListener_Desc());

		fToolkit.createLabel(row, "Owner Column:");
		fOwnerColText = new Combo(row, SWT.BORDER);
		fOwnerColText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fOwnerColText.addModifyListener(createModifyListener_Owner());

		fToolkit.createLabel(row, "Originated Column:");
		fOrigColText = new Combo(row, SWT.BORDER);
		fOrigColText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fOrigColText.addModifyListener(createModifyListener_Orig());

		fToolkit.createLabel(row, "Modified Column:");
		fModColText = new Combo(row, SWT.BORDER);
		fModColText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fModColText.addModifyListener(createModifyListener_Mod());
		
		Composite buttonsRow = fToolkit.createComposite(fSubComposite);
		buttonsRow.setLayout(new GridLayout(3, false));
		buttonsRow.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		
		Label filler = fToolkit.createLabel(buttonsRow, "");
		filler.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		
		fAllAttributesButton = fToolkit.createButton(buttonsRow, "Add All Attributes", SWT.PUSH);
		fAllAttributesButton.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false));
		fAllAttributesButton.addSelectionListener(createAddAllAttributeListener());

		fNewAttributeButton = fToolkit.createButton(buttonsRow, "Add Attribute", SWT.PUSH);
		fNewAttributeButton.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false));
		fNewAttributeButton.addSelectionListener(createNewAttributeListener());

		createAttributeTable();
		createTableContextMenu();
	}

	@Override
	protected void populateTableComboChoices()
	{
		IObject[] tables = fMap.getTableSection().getObjects();
		
		String currentText = fTableText.getText();
		
		fTableText.removeAll();
		
		for(IObject table : tables)
		{
			fTableText.add(table.getObjectName());
		}
		
		fTableText.setText(currentText);
	}
	
	@Override
	protected void populateColumnComboChoices()
	{
		String tableName = fTableText.getText();
		if(tableName == null || tableName.isEmpty())
		{
			setColumnNames(new String[0]);
			return;
		}
		
		Table table = fMap.getTableSection().getTable(tableName);
		if(table == null)
		{
			setColumnNames(new String[0]);
			return;
		}
		
		String[] columnNames = table.getColumnNames();
		
		setColumnNames(columnNames);
	}

	@Override
	protected void setColumnNames(String[] columnNames)
	{
		updateComboSelection(fIdColText, columnNames, typeFocus == null ? "" : typeFocus.getID());
		updateComboSelection(fTypeColText, columnNames, typeFocus == null ? "" : typeFocus.getType());
		updateComboSelection(fNameColText, columnNames, typeFocus == null ? "" : typeFocus.getName());
		updateComboSelection(fRevColText, columnNames, typeFocus == null ? "" : typeFocus.getRevision());
		updateComboSelection(fPrevRevColText, columnNames, typeFocus == null ? "" : typeFocus.getPreviousRevision());
		updateComboSelection(fNextRevColText, columnNames, typeFocus == null ? "" : typeFocus.getNextRevision());
		updateComboSelection(fPolicyColText, columnNames, typeFocus == null ? "" : typeFocus.getPolicy());
		updateComboSelection(fStateColText, columnNames, typeFocus == null ? "" : typeFocus.getState());
		updateComboSelection(fDescColText, columnNames, typeFocus == null ? "" : typeFocus.getDescription());
		updateComboSelection(fOwnerColText, columnNames, typeFocus == null ? "" : typeFocus.getOwner());
		updateComboSelection(fOrigColText, columnNames, typeFocus == null ? "" : typeFocus.getOriginated());
		updateComboSelection(fModColText, columnNames, typeFocus == null ? "" : typeFocus.getModified());
	}

	private SelectionListener createAddAllAttributeListener()
	{
		return new SelectionAdapter() {
			
			@Override
			public void widgetSelected(SelectionEvent e)
			{
				List<String> attrList = MatrixUtils.getTypeAttributes(typeFocus.getObjectName());
				
				if(attrList == null)
				{
					Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
					MessageDialog dialog = new MessageDialog(shell, "ENOVIA Data Not Loaded", null, 
							"You have not loaded the ENOVIA schema information", MessageDialog.WARNING, new String[]{"OK"}, 0);
					dialog.open();
					return;
				}
				
				for(String curAttr : attrList)
				{
					if(typeFocus.getAttributeColumn(curAttr) == null)
					{
						String colName = AdapletConstants.toSQLFormat(curAttr);
						typeFocus.addAttribute(curAttr, colName);
					}
				}
				
				fEditor.refresh();
				fAttributeTable.refresh();
			}
		};
	}

	private void createAttributeTable()
	{
		int colWidth = AdapletConstants.computeSubWidth(2,2);
		
		fAttributeTable = new TableViewer(fSubComposite, SWT.BORDER | SWT.V_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION);
		fAttributeTable.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		fAttributeTable.setContentProvider(new AttributeTableContentProvider());
		fAttributeTable.setColumnProperties(new String[] { "Attribute", "Table Column" });

		TableViewerColumn viewerColumn = new TableViewerColumn(fAttributeTable, SWT.NONE);
		TableColumn col = viewerColumn.getColumn();
		col.setMoveable(false);
		col.setResizable(true);
		col.setText("Attribute");
		col.setWidth(colWidth);
		viewerColumn.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element)
			{
				return (String) element;
			}
		});
		viewerColumn.setEditingSupport(new EditingSupport(fAttributeTable) {
			
			@Override
			protected void setValue(Object element, Object value)
			{
				String oldAttrName = (String) element;
				String newAttrName = (String) value;
				
				if(newAttrName == null || newAttrName.isEmpty())
				{
					return;
				}
				
				String[] attrNames = typeFocus.getAttributeNames();
				
				for(String curAttr : attrNames)
				{
					if(curAttr.equals(newAttrName))
					{
						return;
					}
				}
				
				String oldTabColVal = typeFocus.getAttributeColumn(oldAttrName);
				typeFocus.removeAttribute(oldAttrName);
				typeFocus.addAttribute(newAttrName, oldTabColVal);
				
				fAttributeTable.refresh();
				fEditor.refresh();
			}
			
			@Override
			protected Object getValue(Object element)
			{
				return (String) element;
			}
			
			@Override
			protected CellEditor getCellEditor(Object element)
			{
				return new TextCellEditor(fAttributeTable.getTable());
			}
			
			@Override
			protected boolean canEdit(Object element)
			{
				return true;
			}
		});

		viewerColumn = new TableViewerColumn(fAttributeTable, SWT.NONE);
		col = viewerColumn.getColumn();
		col.setMoveable(false);
		col.setResizable(true);
		col.setText("Table Column");
		col.setAlignment(SWT.RIGHT);
		col.setWidth(colWidth);
		viewerColumn.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element)
			{
				return typeFocus.getAttributeColumn((String) element);
			}
		});
		viewerColumn.setEditingSupport(new EditingSupport(fAttributeTable) {
			
			@Override
			protected void setValue(Object element, Object value)
			{
				String attrName = (String) element;
				String newVal = (String) value;
				
				typeFocus.addAttribute(attrName, newVal);
				fAttributeTable.refresh();
				fEditor.refresh();
			}
			
			@Override
			protected Object getValue(Object element)
			{
				return typeFocus.getAttributeColumn((String) element);
			}
			
			@Override
			protected CellEditor getCellEditor(Object element)
			{
				return new TextCellEditor(fAttributeTable.getTable());
			}
			
			@Override
			protected boolean canEdit(Object element)
			{
				return true;
			}
		});

		fAttributeTable.getTable().setHeaderVisible(true);

		fAttributeTable.setInput(new AttributeTableInput(typeFocus));
	}

	private void createTableContextMenu()
	{
		Menu menu = new Menu(fAttributeTable.getTable());

		MenuItem item = new MenuItem(menu, SWT.PUSH);
		item.setText("Remove Attribute");
		item.addSelectionListener(new SelectionAdapter() {

			@Override
			public void widgetSelected(SelectionEvent e)
			{
				IStructuredSelection selection = (IStructuredSelection) fAttributeTable.getSelection();
				String attrName = (String) selection.getFirstElement();

				typeFocus.removeAttribute(attrName);

				fAttributeTable.refresh();
				fEditor.refresh();
			}
		});

		fAttributeTable.getTable().setMenu(menu);
	}

	private SelectionListener createNewAttributeListener()
	{
		return new SelectionAdapter() {

			@Override
			public void widgetSelected(SelectionEvent e)
			{
				Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();

				NewAttributeDialog dialog = new NewAttributeDialog(shell, Section.TYPE, typeFocus.getObjectName());

				dialog.create();
				dialog.open();

				if (dialog.getReturnCode() == Window.OK)
				{
					typeFocus.addAttribute(dialog.getAttribute(), dialog.getColumn());

					fAttributeTable.refresh();
					fEditor.refresh();
				}
			}
		};
	}

//	private ModifyListener createModifyListener_TypeName()
//	{
//		return new ModifyListener() {
//
//			@Override
//			public void modifyText(ModifyEvent e)
//			{
//				if (typeFocus != null)
//				{
//					typeFocus.setTypeName(fTypeNameText.getText());
//					fMap.notifyListeners(Section.TYPE);
//					fEditor.refresh();
//				}
//			}
//		};
//	}

	private ModifyListener createModifyListener_Table()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setTableName(fTableText.getText());
					populateColumnComboChoices();
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_Derives()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setDerives(fDerivesText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_ID()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setID(fIdColText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_Type()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setType(fTypeColText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_TypeAlias()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setTypeAlias(fTypeAliasText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_Name()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setName(fNameColText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_Rev()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setRevision(fRevColText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_Prev()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setPreviousRevision(fPrevRevColText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_Next()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setNextRevision(fNextRevColText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_Policy()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setPolicy(fPolicyColText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_State()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setState(fStateColText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_Desc()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setDescription(fDescColText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_Owner()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setOwner(fOwnerColText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_Orig()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setOriginated(fOrigColText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_Mod()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (typeFocus != null)
				{
					typeFocus.setModified(fModColText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	@Override
	protected void updateFields()
	{
		typeFocus = (Type) fFocusObject;

		if (typeFocus == null)
		{
			fTypeNameText.setText("");
			fTableText.setText("");
			fDerivesText.setText("");
			fIdColText.setText("");
			fTypeColText.setText("");
			fTypeAliasText.setText("");
			fNameColText.setText("");
			fRevColText.setText("");
			fPrevRevColText.setText("");
			fNextRevColText.setText("");
			fPolicyColText.setText("");
			fStateColText.setText("");
			fDescColText.setText("");
			fOwnerColText.setText("");
			fOrigColText.setText("");
			fModColText.setText("");
		}
		else
		{
			fTypeNameText.setText(typeFocus.getTypeName());
			fTableText.setText(typeFocus.getTableName());
			fDerivesText.setText(typeFocus.getDerives());
			fIdColText.setText(typeFocus.getID());
			fTypeColText.setText(typeFocus.getType());
			fTypeAliasText.setText(typeFocus.getTypeAlias());
			fNameColText.setText(typeFocus.getName());
			fRevColText.setText(typeFocus.getRevision());
			fPrevRevColText.setText(typeFocus.getPreviousRevision());
			fNextRevColText.setText(typeFocus.getNextRevision());
			fPolicyColText.setText(typeFocus.getPolicy());
			fStateColText.setText(typeFocus.getState());
			fDescColText.setText(typeFocus.getDescription());
			fOwnerColText.setText(typeFocus.getOwner());
			fOrigColText.setText(typeFocus.getOriginated());
			fModColText.setText(typeFocus.getModified());
		}

		fAttributeTable.setInput(new AttributeTableInput(typeFocus));
		
		populateTableComboChoices();
		populateColumnComboChoices();
		populateDerivedComboChoices();
	}

	private class AttributeTableContentProvider implements IStructuredContentProvider
	{

		@Override
		public void dispose()
		{

		}

		@Override
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
		{

		}

		@Override
		public Object[] getElements(Object inputElement)
		{
			return ((AttributeTableInput) inputElement).getData();
		}

	}

	private class AttributeTableInput
	{
		private Type fInput;

		public AttributeTableInput(Type type)
		{
			fInput = type;
		}

		public String[] getData()
		{
			if (fInput == null)
			{
				return new String[0];
			}
			return fInput.getAttributeNames();
		}
	}

	@Override
	public void acceptChange(Section changedSection)
	{
		switch(changedSection)
		{
		case TABLE:
			populateTableComboChoices();
			populateColumnComboChoices();
			break;
		case TYPE:
			populateDerivedComboChoices();
			break;
		default:
			break;
		}
	}

	private void populateDerivedComboChoices()
	{
		if(typeFocus == null)
		{
			return;
		}
		
		String curType = typeFocus.getTypeName();
		String currentText = fDerivesText.getText();
		
		fDerivesText.removeAll();
		
		IObject[] iObjects = fMap.getTypeSection().getObjects();
		
		for(IObject aObject : iObjects)
		{
			if(!curType.equals(aObject.getObjectName()))
			{
				fDerivesText.add(aObject.getObjectName());
			}
		}
		
		fDerivesText.setText(currentText);
	}

}
